package de.tmahr.android;

import java.util.ArrayList;
import java.util.Random;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * Diese Klasse simuliert bewegte Kreise und zeichnet diese mittels
 * Canvas-Technik auf den Bildschirm. Die Simulation findet außerhalb des
 * UI-Threads in einem nebenläufigen Threads statt.
 */
public class AdvancedGraphicsTest extends Activity
{
	private RenderView renderView;
	private Random rand = new Random();

	private void log(String text)
	{
		Log.d(AdvancedGraphicsTest.class.getSimpleName(), text);
	}

	/**
	 * Definiert die für die Animation verwendeten Kreise.
	 */
	class Kreis
	{
		float x, y, vx, vy;
		float radius;
		int xMax, yMax;
		int r, g, b, a; // Farben: rot, grün, blau, alpha

		Kreis(int xMax, int yMax)
		{
			this.xMax = xMax;
			this.yMax = yMax;
			x = xMax * rand.nextFloat();
			y = yMax * rand.nextFloat();

			radius = 10 * (0.1f + rand.nextFloat());

			float vMax = 10;
			vx = vMax * rand.nextFloat();
			vy = vMax * rand.nextFloat();

			r = rand.nextInt(256);
			g = rand.nextInt(256);
			b = rand.nextInt(256);
			a = rand.nextInt(256);
		}

		void bewege()
		{
			x += vx;
			if (x < 0 || x >= xMax)
			{
				vx = -vx;
			}
			y += vy;
			if (y < 0 || y >= yMax)
			{
				vy = -vy;
			}
		}
	}

	/**
	 * Diese spezialisierte SurfaceView bewegt die Kreise und stellt sie auf dem
	 * Bildschirm dar. Eine SurfaceView bietet einen Zugriff auf den
	 * Speicherbereich (Surface), der von Android für die Bildschirmdarstellung
	 * verwendet wird.
	 */
	class RenderView extends SurfaceView implements Runnable
	{
		ArrayList<Kreis> kreise = null;
		private Paint paint;

		/**
		 * Da wir in einem eigenen Thread auf Surface zugreifen wollen,
		 * benötigen wir einen SurfaceHolder, der den Zugriff auf den Speicher
		 * regelt.
		 */
		SurfaceHolder holder;
		Thread thread = null;
		volatile boolean running = false;

		public RenderView(Context c)
		{
			super(c);
			holder = getHolder(); // Wir holen uns über SurfaceView.getHolder()
									// Zugriff auf den Grafikspeicher
			paint = new Paint();
			paint.setAntiAlias(true);
		}

		public void resume()
		{
			running = true;
			thread = new Thread(this);
			thread.start();
			log("Thread gestartet");
		}

		public void pause()
		{
			running = false;
			while (true)
			{
				try
				{
					thread.join();
					break;
				}
				catch (InterruptedException e)
				{
				}
			}
			log("Thread angehalten");
		}

		@Override
		public void run()
		{
			while (running)
			{
				if (!holder.getSurface().isValid())
				{
					continue;
				}
				Canvas c = holder.lockCanvas(); // Surface für Schreibzugriff
												// sperren
				naechsterSchritt(c);
				holder.unlockCanvasAndPost(c); // Surface wieder freigeben
			}
		}

		private void naechsterSchritt(Canvas canvas)
		{
			if (kreise == null)
			{
				kreise = new ArrayList<Kreis>();
				for (int i = 0; i < 100; i++)
				{
					kreise.add(new Kreis(canvas.getWidth(), canvas.getHeight()));
				}
			}

			paint.setStyle(Style.FILL);

			canvas.drawRGB(0, 0, 0);
			for (Kreis k : kreise)
			{
				paint.setARGB(k.a, k.r, k.g, k.b);
				canvas.drawCircle(k.x, k.y, k.radius, paint);
				k.bewege();
			}
		}
	}

	@Override
	public void onCreate(Bundle b)
	{
		super.onCreate(b);
		setTitle(AdvancedGraphicsTest.class.getSimpleName());
		renderView = new RenderView(this);
		setContentView(renderView);
	}

	@Override
	protected void onPause()
	{
		super.onPause();
		renderView.pause();
	}

	@Override
	protected void onResume()
	{
		super.onResume();
		renderView.resume();
	}
}
